package com.game.plus2048;

import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

public class Game {

	public int Counttouch;
	private int[][] game, gameUndo;
	private Random rand;
	private int time, score, remainingUndo, height, width, win_score, glowId;
	private Timer timer;
	private boolean gameLost = false, gameWon = false;

	public Game(int gridHeight, int gridWidth, int wscore) {

		rand = new Random();
		score = 0;
		time = 0;
		height = gridHeight;
		width = gridWidth;
		game = new int[gridHeight][gridWidth];
		gameUndo = new int[gridHeight][gridWidth];
		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width; j++) {

				game[i][j] = 0;

			}

		}
		timer = new Timer();
		timer.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				incTime(1);
			}
		}, 0, 1000);

	}

	public Game(int scoreR, int timeR, int[][] gameState, int rUndo,
			int wscore, int h, int w) {

		rand = new Random();
		score = scoreR;
		time = timeR;
		height = h;
		width = w;
		game = new int[h][w];
		gameUndo = new int[h][w];
		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width; j++) {

				game[i][j] = gameState[i][j];

			}

		}
		remainingUndo = rUndo;
		timer = new Timer();
		timer.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				incTime(1);
			}
		}, 0, 1000);

	}

	public boolean onUpSwipe() {

		Counttouch += 1;
		int[][] gameStateBefore = new int[height][width];

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width; j++) {

				gameStateBefore[i][j] = this.game[i][j];

			}

		}

		for (int i = 0; i < width; i++) {

			for (int j = 0; j < height - 1; j++) {

				for (int k = 0; k < height - 1 - j; k++) {

					if (game[j][i] == 0) {

						for (int l = 0; l < height - 1 - j; l++) {

							game[j + l][i] = game[j + l + 1][i];
							game[j + l + 1][i] = 0;

						}

					} else {

						break;

					}

				}

			}

			for (int j = 0; j < height - 1; j++) {

				if (game[j][i] == game[j + 1][i]) {

					game[j][i] += game[j + 1][i];
					incScore(game[j][i]);
					game[j + 1][i] = 0;
					if (game[j][i] == 2048) {

						setWon();

					}

				}

			}

			for (int j = 0; j < height - 1; j++) {

				for (int k = 0; k < height - 1 - j; k++) {

					if (game[j][i] == 0) {

						for (int l = 0; l < height - 1 - j; l++) {

							game[j + l][i] = game[j + l + 1][i];
							game[j + l + 1][i] = 0;

						}

					} else {

						break;

					}

				}

			}

		}

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width; j++) {

				if (gameStateBefore[i][j] != game[i][j] && gameHasSpaces()) {

					for (int k = 0; k < height; k++) {

						for (int l = 0; l < width; l++) {

							gameUndo[k][l] = gameStateBefore[k][l];

						}

					}

					nextClearSpace();

					if (!gameHasSpaces() && !hasMoves()) {

						setLost();

					}

					return true;

				}

			}

		}

		if (!gameHasSpaces() && !hasMoves()) {

			setLost();

		}

		return false;

	}

	public boolean onDownSwipe() {
		Counttouch +=1;
		int[][] gameStateBefore = new int[height][width];

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width; j++) {

				gameStateBefore[i][j] = this.game[i][j];

			}

		}

		for (int i = 0; i < width; i++) {

			for (int j = 0; j < height - 1; j++) {

				for (int k = 0; k < height - 1 - j; k++) {

					if (game[height - 1 - j][i] == 0) {

						for (int l = 0; l < height - 1 - j; l++) {

							game[height - 1 - j - l][i] = game[height - 1 - j
									- l - 1][i];
							game[height - 1 - j - l - 1][i] = 0;

						}

					} else {

						break;

					}

				}

			}

			for (int j = 0; j < height - 1; j++) {

				if (game[height - 1 - j][i] == game[height - 1 - j - 1][i]) {

					game[height - 1 - j][i] += game[height - 1 - j - 1][i];
					incScore(game[height - 1 - j][i]);
					game[height - 1 - j - 1][i] = 0;
					if (game[height - 1 - j][i] == 2048) {

						setWon();

					}

				}

			}

			for (int j = 0; j < height - 1; j++) {

				for (int k = 0; k < height - 1 - j; k++) {

					if (game[height - 1 - j][i] == 0) {

						for (int l = 0; l < height - 1 - j; l++) {

							game[height - 1 - j - l][i] = game[height - 1 - j
									- l - 1][i];
							game[height - 1 - j - l - 1][i] = 0;

						}

					} else {

						break;

					}

				}

			}

		}

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width; j++) {

				if (gameStateBefore[i][j] != game[i][j] && gameHasSpaces()) {

					for (int k = 0; k < height; k++) {

						for (int l = 0; l < width; l++) {

							gameUndo[k][l] = gameStateBefore[k][l];

						}

					}

					nextClearSpace();

					if (!gameHasSpaces() && !hasMoves()) {

						setLost();

					}

					return true;

				}

			}

		}

		if (!gameHasSpaces() && !hasMoves()) {

			setLost();

		}

		return false;

	}

	public boolean onLeftSwipe() {
		Counttouch +=1;
		int[][] gameStateBefore = new int[height][width];

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width; j++) {

				gameStateBefore[i][j] = this.game[i][j];

			}

		}

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width - 1; j++) {

				for (int k = 0; k < width - 1 - j; k++) {

					if (game[i][j] == 0) {

						for (int l = 0; l < width - 1 - j; l++) {

							game[i][j + l] = game[i][j + l + 1];
							game[i][j + l + 1] = 0;

						}

					} else {

						break;

					}

				}

			}

			for (int j = 0; j < width - 1; j++) {

				if (game[i][j] == game[i][j + 1]) {

					game[i][j] += game[i][j + 1];
					incScore(game[i][j]);
					game[i][j + 1] = 0;
					if (game[i][j] == 2048) {

						setWon();

					}

				}

			}

			for (int j = 0; j < width - 1; j++) {

				for (int k = 0; k < width - 1 - j; k++) {

					if (game[i][j] == 0) {

						for (int l = 0; l < width - 1 - j; l++) {

							game[i][j + l] = game[i][j + l + 1];
							game[i][j + l + 1] = 0;

						}

					} else {

						break;

					}

				}

			}

		}

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width; j++) {

				if (gameStateBefore[i][j] != game[i][j] && gameHasSpaces()) {

					for (int k = 0; k < height; k++) {

						for (int l = 0; l < width; l++) {

							gameUndo[k][l] = gameStateBefore[k][l];

						}

					}

					nextClearSpace();

					if (!gameHasSpaces() && !hasMoves()) {

						setLost();

					}

					return true;

				}

			}

		}

		if (!gameHasSpaces() && !hasMoves()) {

			setLost();

		}

		return false;

	}

	public boolean onRightSwipe() {
		Counttouch +=1;
		int[][] gameStateBefore = new int[height][width];

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width; j++) {

				gameStateBefore[i][j] = this.game[i][j];

			}

		}

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width - 1; j++) {

				for (int k = 0; k < width - 1 - j; k++) {

					if (game[i][width - 1 - j] == 0) {

						for (int l = 0; l < width - 1 - j; l++) {

							game[i][width - 1 - j - l] = game[i][width - 1 - j
									- l - 1];
							game[i][width - 1 - j - l - 1] = 0;

						}

					} else {

						break;

					}

				}

			}

			for (int j = 0; j < width - 1; j++) {

				if (game[i][width - 1 - j] == game[i][width - 1 - j - 1]) {

					game[i][width - 1 - j] += game[i][width - 1 - j - 1];
					incScore(game[i][width - 1 - j]);
					game[i][width - 1 - j - 1] = 0;
					if (game[i][width - 1 - j] == 2048) {

						setWon();

					}

				}

			}

			for (int j = 0; j < width - 1; j++) {

				for (int k = 0; k < width - 1 - j; k++) {

					if (game[i][width - 1 - j] == 0) {

						for (int l = 0; l < width - 1 - j; l++) {

							game[i][width - 1 - j - l] = game[i][width - 1 - j
									- l - 1];
							game[i][width - 1 - j - l - 1] = 0;

						}

					} else {

						break;

					}

				}

			}

		}

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width; j++) {

				if (gameStateBefore[i][j] != game[i][j]) {

					for (int k = 0; k < height; k++) {

						for (int l = 0; l < width; l++) {

							gameUndo[k][l] = gameStateBefore[k][l];

						}

					}

					nextClearSpace();

					if (!gameHasSpaces() && !hasMoves()) {

						setLost();

					}

					return true;

				}

			}

		}

		if (!gameHasSpaces() && !hasMoves()) {

			setLost();

		}

		return false;

	}

	public boolean undoLastMove() {

		if (remainingUndo > 0) {

			for (int k = 0; k < height; k++) {

				for (int l = 0; l < width; l++) {

					game[k][l] = gameUndo[k][l];

				}

			}

			remainingUndo--;
			return true;

		}

		return false;

	}

	public boolean gameHasSpaces() {

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width; j++) {

				if (game[i][j] == 0) {

					return true;

				}

			}

		}

		return false;

	}

	private boolean hasMoves() {

		for (int i = 0; i < height; i++) {

			for (int j = 0; j < width - 1; j++) {

				if (game[i][j] == game[i][j + 1]) {

					return true;

				}

			}

		}

		for (int i = 0; i < width; i++) {

			for (int j = 0; j < height - 1; j++) {

				if (game[j][i] == game[j + 1][i]) {

					return true;

				}

			}

		}

		return false;

	}

	protected void nextClearSpace() {

		while (true) {

			int i = rand.nextInt(height), j = rand.nextInt(width), newNumber = (rand
					.nextInt(2) + 1) * 2;
			if (game[i][j] == 0) {

				game[i][j] = newNumber;
				glowId = (i * width) + j;
				break;

			}

		}

	}

	private void incTime(int increment) {

		time += increment;

	}

	public int getTime() {

		return time;

	}

	public String getTimeF() {

		final int hr = (time / 3600);

		final int rem = (time % 3600);

		final int mn = rem / 60;

		final int sec = rem % 60;

		String time;

		if (hr > 0) {

			String hrStr = (hr < 10 ? "0" : "") + hr;
			String mnStr = (mn < 10 ? "0" : "") + mn;
			String secStr = (sec < 10 ? "0" : "") + sec;
			time = hrStr + "h" + mnStr + "m" + secStr + "s";

		} else if (mn > 0) {

			String mnStr = (mn < 10 ? "0" : "") + mn;
			String secStr = (sec < 10 ? "0" : "") + sec;
			time = mnStr + "m" + secStr + "s";

		} else {

			String secStr = (sec < 10 ? "0" : "") + sec;
			time = secStr + "s";

		}

		return time;

	}

	private void incScore(int increment) {

		score += increment;

	}
	
	public int getCountTouch()
	{
		return Counttouch;
	}

	public int getScore() {

		return score;

	}

	public int[][] getGameState() {

		return game;

	}

	private void setLost() {

		gameLost = true;

	}

	private void setWon() {

		gameWon = true;

	}

	public boolean isLost() {

		return gameLost;

	}

	public boolean isWon() {

		return gameWon;

	}

	public int getUndos() {

		return remainingUndo;

	}

	public int getHeight() {

		return height;

	}

	public int getWidth() {

		return width;

	}

	public int getWinScore() {

		return win_score;

	}

	public int getGlowId() {

		return glowId;

	}

}
